home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / games_d / oasys.zip / OAI.C < prev    next >
C/C++ Source or Header  |  1991-04-06  |  18KB  |  920 lines

  1. #include    <io.h>
  2. #include    <fcntl.h>
  3. #include    <stdlib.h>
  4. #include    <ctype.h>
  5. #include    <assert.h>
  6. #include    <time.h>
  7. #include    <bios.h>
  8. #include    <string.h>
  9. #include    <rwlib.h>
  10. #include    "ins.h"
  11.  
  12. const MAXWORDS = 64;
  13. const MAXSTACK = 1024;
  14. const MAXBUF = 512;
  15.  
  16. union var
  17. {
  18.     int i;
  19.     dlist *o;
  20.     var *v;
  21. };
  22.  
  23. struct phrase
  24. {
  25.     int nwords;
  26.     int *words;
  27. };
  28.  
  29. struct Class
  30. {
  31.     int nphrases;
  32.     phrase *phrases;
  33. };
  34.  
  35. struct instruction
  36. {
  37.     int op;
  38.     int i;
  39. };
  40.  
  41. struct method
  42. {
  43.     int type;
  44.     int nargs;
  45.     int *argtypes;
  46.     int *selectors;
  47.     int nvars;
  48.     int *vartypes;
  49.     int nverbs;
  50.     phrase *verbs;
  51.     int noselect;
  52.     int ninstructions;
  53.     instruction *instructions;
  54. };
  55.  
  56. int file;
  57. char **strings;
  58. var *vars;
  59. int nvars;
  60. int nproperties;
  61. int nvocab;
  62. char **vocab;
  63. int comma;
  64. int nwords;
  65. int words[MAXWORDS];
  66. var nouns[MAXWORDS];
  67. char buf[MAXBUF];
  68. char filename[MAXBUF] = "oasys.game";
  69. Class *classes;
  70. int nclasses;
  71. int nmethods;
  72. int initmethod;
  73. method *methods;
  74. int nnouns;
  75. int selectaddresseemethod;
  76. dlist objects;
  77. var stack[MAXSTACK];
  78. int sp;
  79. int restart;
  80. int *vartypes;
  81. int *propertytypes;
  82. var nullv;
  83.  
  84. inline void chkobject (dlist *o)
  85. {
  86.     if (!o)
  87.         perr ("ERROR - Nonexistent object");
  88. }
  89.  
  90. inline var *propertyptr (dlist *o,int i)
  91. {
  92.     chkobject (o);
  93.     return ((var *)(((char *)o) + sizeof (dlist) + sizeof (int))) + i;
  94. }
  95.  
  96. inline var *property (dlist *o,int i)
  97. {
  98.     if (o == 0)
  99.         return &nullv;
  100.     return ((var *)(((char *)o) + sizeof (dlist) + sizeof (int))) + i;
  101. }
  102.  
  103. inline int *classnoptr (dlist *o)
  104. {
  105.     chkobject (o);
  106.     return (int *)(o+1);
  107. }
  108.  
  109. inline int classno (dlist *o)
  110. {
  111.     if (o == 0)
  112.         return -1;
  113.     return *((int *)(o+1));
  114. }
  115.  
  116. readint ()
  117. {
  118.     int i;
  119.     Read (file,&i,sizeof (int));
  120.     return i;
  121. }
  122.  
  123. findvocab (char *s)
  124. {
  125.     char **result = (char **)bsearch (&s,vocab,nvocab,sizeof (char*),strpcmp);
  126.     if (!result)
  127.         return -1;
  128.     return (int)(result - vocab);
  129. }
  130.  
  131. int printx;
  132. int printy;
  133.  
  134. void printnewline ()
  135. {
  136.     putchar ('\n');
  137.     printx = 0;
  138.     printy++;
  139.     if (printy == 24)
  140.     {
  141.         printf ("MORE...");
  142.         bioskey (0);
  143.         printf ("\r       \r");
  144.         printy = 0;
  145.     }
  146. }
  147.  
  148. void printchar (int c)
  149. {
  150.     static char buf[84];
  151.     static i;
  152.     switch (c)
  153.     {
  154.         case '\n':
  155.         case ' ':
  156.             if (printx+i > 78 && i <= 79)
  157.                 printnewline ();
  158.             if (printx)
  159.             {
  160.                 putchar (' ');
  161.                 printx++;
  162.             }
  163.             buf[i] = 0;
  164.             printf ("%s",buf);
  165.             printx += i;
  166.             i = 0;
  167.             if (c == '\n')
  168.                 printnewline ();
  169.             break;
  170.         default:
  171.             buf[i++] = c;
  172.             if (i == sizeof (buf))
  173.                 perr ("ERROR - Word too long");
  174.     }
  175. }
  176.  
  177. void print (char *s)
  178. {
  179.     while (*s)
  180.         printchar (*s++);
  181. }
  182.  
  183. void print (int i)
  184. {
  185.     char s[12];
  186.     sprintf (s,"%d",i);
  187.     print (s);
  188. }
  189.  
  190. void input (char *s)
  191. {
  192.     printx = printy = 0;
  193.     gets (s);
  194. }
  195.  
  196. void getinput ()
  197. {
  198.     int i,j,k,c;
  199. REDO:
  200.     print ("> ");
  201.     input (buf);
  202.     for (i=0 ; buf[i] ; i++)
  203.         if (buf[i] == '\t' || buf[i] == '\'' || buf[i] == '"')
  204.             buf[i] = ' ';
  205.     nwords = 0;
  206.     comma = -1;
  207.     for (i=0 ;;)
  208.     {
  209.         while (buf[i] == ' ')
  210.             i++;
  211.         if (!buf[i])
  212.             break;
  213.         if (buf[i] == ',')
  214.         {
  215.             if (comma >= 0)
  216.             {
  217.                 print ("Commands should not have more than one comma.\n");
  218.                 goto REDO;
  219.             }
  220.             comma = nwords;
  221.             i++;
  222.             continue;
  223.         }
  224.         j = i;
  225.         do
  226.         {
  227.             buf[j] = tolower (buf[j]);
  228.             j++;
  229.         }
  230.         while (buf[j] && buf[j] != ' ' && buf[j] != ',');
  231.         c = buf[j];
  232.         buf[j] = 0;
  233.         if (strcmp (buf+i,"the"))
  234.         {
  235.             if (buf[i] == '-')
  236.             {
  237.                 print ("Negative numbers not implemented.\n");
  238.                 goto REDO;
  239.             }
  240.             if (isdigit (buf[i]))
  241.                 words[nwords++] = ~atoi (buf+i);
  242.             else
  243.             {
  244.                 k = findvocab (buf+i);
  245.                 if (k < 0)
  246.                 {
  247.                     print ("I don't understand the word \"");
  248.                     print (buf+i);
  249.                     print ("\".\n");
  250.                     goto REDO;
  251.                 }
  252.                 if (nwords == MAXWORDS)
  253.                 {
  254.                     print ("There were too many words in that command.\n");
  255.                     goto REDO;
  256.                 }
  257.                 words[nwords++] = k;
  258.             }
  259.         }
  260.         buf[j] = c;
  261.         i = j;
  262.     }
  263. }
  264.  
  265. findclass (int *words,int nwords)
  266. {
  267.     int i,j;
  268.     for (i=0 ; i<nclasses ; i++)
  269.         for (j=0 ; j<classes[i].nphrases ; j++)
  270.             if (nwords == classes[i].phrases[j].nwords &&
  271.                     !memcmp (words,classes[i].phrases[j].words,nwords * sizeof (int)))
  272.                 return i;
  273.     return -1;
  274. }
  275.  
  276. void writeint (int i)
  277. {
  278.     Write (file,&i,sizeof (int));
  279. }
  280.  
  281. void writevars (int n,var *vars,int *vartypes)
  282. {
  283.     dlist *o;
  284.     int i;
  285.     do
  286.     {
  287.         var v = *vars;
  288.         if (*vartypes == T_OBJECT)
  289.         {
  290.             for (o=objects.next,i=0 ; o!=&objects ; o=o->next,i++)
  291.                 if (v.o == o)
  292.                 {
  293.                     v.i = i;
  294.                     break;
  295.                 }
  296.             if (o == &objects)
  297.                 v.i = -1;
  298.         }
  299.         Write (file,&v,sizeof (v));
  300.         vars++;
  301.         vartypes++;
  302.     }
  303.     while (--n > 0);
  304. }
  305.  
  306. void savegame ()
  307. {
  308.     dlist *o;
  309.     print ("File name? [");
  310.     print (filename);
  311.     print ("] ");
  312.     input (buf);
  313.     if (buf[0] == 0)
  314.         strcpy (buf,filename);
  315.     file = open (buf,O_RDWR | O_BINARY | O_CREAT | O_TRUNC,0777);
  316.     if (file < 0)
  317.     {
  318.         print ("Can't create file.\n");
  319.         return;
  320.     }
  321.     strcpy (filename,buf);
  322.     Write (file,"oas\1",4);
  323.     writevars (nvars,vars,vartypes);
  324.     writeint (objects.len ());
  325.     for (o=objects.next ; o!=&objects ; o=o->next)
  326.     {
  327.         writeint (*classnoptr (o));
  328.         writevars (nproperties,propertyptr (o,0),propertytypes);
  329.     }
  330.     close (file);
  331. }
  332.  
  333. void chkvars (int n,var *vars,int *vartypes,dlist *o)
  334. {
  335.     do
  336.     {
  337.         if (*vartypes == T_OBJECT && vars->o == o)
  338.             vars->o = 0;
  339.         vars++;
  340.         vartypes++;
  341.     }
  342.     while (--n > 0);
  343. }
  344.  
  345. void restorevars (int n,var *vars,int *vartypes)
  346. {
  347.     dlist *o;
  348.     int i;
  349.     do
  350.     {
  351.         if (*vartypes == T_OBJECT)
  352.         {
  353.             if (vars->i < 0)
  354.                 vars->o = 0;
  355.             else
  356.             {
  357.                 for (o=objects.next,i=0 ; i!=vars->i ; o=o->next,i++)
  358.                     assert (o!=&objects);
  359.                 vars->o = o;
  360.             }
  361.         }
  362.         vars++;
  363.         vartypes++;
  364.     }
  365.     while (--n > 0);
  366. }
  367.  
  368. loadgame ()
  369. {
  370.     int i;
  371.     char gamecode[4];
  372.     dlist *o;
  373.     print ("File name? [");
  374.     print (filename);
  375.     print ("] ");
  376.     input (buf);
  377.     if (buf[0] == 0)
  378.         strcpy (buf,filename);
  379.     file = open (buf,O_RDWR | O_BINARY);
  380.     if (file < 0)
  381.     {
  382.         print ("Can't open file.\n");
  383.         return FALSE;
  384.     }
  385.     Read (file,gamecode,4);
  386.     if (memcmp (gamecode,"oas\1",4))
  387.     {
  388.         print ("Not a saved position for this game.\n");
  389.         close (file);
  390.         return FALSE;
  391.     }
  392.     strcpy (filename,buf);
  393.     objects.free ();
  394.     Read (file,vars,nvars * sizeof (var));
  395.     i = readint ();
  396.     do
  397.     {
  398.         o = (dlist *)new char[sizeof (dlist) + sizeof (int) +
  399.                 nproperties * sizeof (var)];
  400.         memset (((char *)o) + sizeof (dlist) + sizeof (int),0,
  401.                 nproperties * sizeof (var));
  402.         *classnoptr (o) = readint ();
  403.         Read (file,propertyptr (o,0),nproperties * sizeof (var));
  404.         objects += o;
  405.     }
  406.     while (--i > 0);
  407.     close (file);
  408.     restorevars (nvars,vars,vartypes);
  409.     for (o=objects.next ; o!=&objects ; o=o->next)
  410.         restorevars (nproperties,propertyptr (o,0),propertytypes);
  411.     return TRUE;
  412. }
  413.  
  414. getyn (char *s)
  415. {
  416.     for (;;)
  417.     {
  418.         print (s);
  419.         input (buf);
  420.         if (buf[0] == 'y' || buf[0] == 'Y')
  421.             return TRUE;
  422.         if (buf[0] == 'n' || buf[0] == 'N')
  423.             return FALSE;
  424.     }
  425. }
  426.  
  427. var applymethod (dlist *o,int methodno,var *argv)
  428. {
  429.     var v;
  430.     int pc;
  431.     dlist *o2,*o3;
  432.     instruction I;
  433.     int i;
  434.     if (o == 0 && methodno != initmethod)
  435.         return nullv;
  436.     method *m = &methods[methodno];
  437.     int bp = sp;
  438.     memset (stack+bp,0,m->nvars + sizeof (var));
  439.     sp += m->nvars;
  440.     for (pc=0 ; pc!=m->ninstructions ; pc++)
  441.     {
  442.         assert (sp >= 0);
  443.         if (sp >= MAXSTACK)
  444.             perr ("ERROR - Stack overflow");
  445.         I = m->instructions[pc];
  446.         switch (I.op)
  447.         {
  448.             case I_JMP:
  449.                 pc += I.i;
  450.                 break;
  451.             case I_JF:
  452.                 if (!stack[--sp].i)
  453.                     pc += I.i;
  454.                 break;
  455.             case I_JT:
  456.                 if (stack[--sp].i)
  457.                     pc += I.i;
  458.                 break;
  459.             case I_INT:
  460.                 stack[sp++].i = I.i;
  461.                 break;
  462.             case I_OR:
  463.                 sp--;
  464.                 stack[sp-1].i = stack[sp-1].i || stack[sp].i;
  465.                 break;
  466.             case I_AND:
  467.                 sp--;
  468.                 stack[sp-1].i = stack[sp-1].i && stack[sp].i;
  469.                 break;
  470.             case I_NOT:
  471.                 stack[sp-1].i = !stack[sp-1].i;
  472.                 break;
  473.             case I_REFLOCALVAR:
  474.                 stack[sp++].v = stack + bp + I.i;
  475.                 break;
  476.             case I_REFARG:
  477.                 stack[sp++].v = argv + I.i;
  478.                 break;
  479.             case I_REFGLOBALVAR:
  480.                 stack[sp++].v = vars + I.i;
  481.                 break;
  482.             case I_REFPROPERTY:
  483.                 stack[sp-1].v = property (stack[sp-1].o,I.i);
  484.                 break;
  485.             case I_DEREF:
  486.                 stack[sp-1] = *stack[sp-1].v;
  487.                 break;
  488.             case I_CALLPROC:
  489.                 applymethod (stack[sp - methods[I.i].nargs - 1].o,I.i,
  490.                         stack + sp - methods[I.i].nargs);
  491.                 if (restart)
  492.                     return nullv;
  493.                 sp -= methods[I.i].nargs + 1;
  494.                 break;
  495.             case I_CALLFUNC:
  496.                 v = applymethod (stack[sp - methods[I.i].nargs - 1].o,I.i,
  497.                         stack + sp - methods[I.i].nargs);
  498.                 if (restart)
  499.                     return nullv;
  500.                 sp -= methods[I.i].nargs + 1;
  501.                 stack[sp++] = v;
  502.                 break;
  503.             case I_ASSIGN:
  504.                 sp -= 2;
  505.                 *stack[sp].v = stack[sp+1];
  506.                 break;
  507.             case I_DESTROY:
  508.                 o2 = stack[--sp].o;
  509.                 chkobject (o2);
  510.                 o2->remove ();
  511.                 for (o3=objects.next ; o3!=&objects ; o3=o3->next)
  512.                     chkvars (nproperties,propertyptr (o3,0),propertytypes,o2);
  513.                 chkvars (nvars,vars,vartypes,o2);
  514.                 break;
  515.             case I_CREATE:
  516.                 o2 = (dlist *)new char[sizeof (dlist) + sizeof (int) +
  517.                         nproperties * sizeof (var)];
  518.                 memset (((char *)o2) + sizeof (dlist) + sizeof (int),0,
  519.                         nproperties * sizeof (var));
  520.                 *classnoptr (o2) = I.i;
  521.                 objects += o2;
  522.                 stack[sp++].o = o2;
  523.                 break;
  524.             case I_QUIT:
  525.                 if (!getyn ("Are you sure? (Y/N) "))
  526.                     break;
  527.             case I_EXIT:
  528.                 restart = TRUE;
  529.                 return nullv;
  530.             case I_THIS:
  531.                 stack[sp++].o = o;
  532.                 break;
  533.             case I_RETFUNC:
  534.                 v = stack[--sp];
  535.             case I_RETPROC:
  536.                 assert (sp == bp+m->nvars);
  537.                 sp = bp;
  538.                 return v;
  539.             case I_EXISTS:
  540.                 stack[sp-1].i = (stack[sp-1].o != 0);
  541.                 break;
  542.             case I_OBJECT:
  543.                 o2 = 0;
  544.                 i = stack[sp-1].i;
  545.                 if (i > 0)
  546.                 {
  547.                     for (o2=objects.next ; i>1 && o2!=&objects ; o2=o2->next,i--)
  548.                         ;
  549.                     if (i > 1)
  550.                         o2 = 0;
  551.                 }
  552.                 stack[sp-1].o = o2;
  553.                 break;
  554.             case I_PRINTINT:
  555.                 print (stack[--sp].i);
  556.                 break;
  557.             case I_PRINTSTR:
  558.                 print (strings[stack[--sp].i]);
  559.                 break;
  560.             case I_SAVE:
  561.                 savegame ();
  562.                 break;
  563.             case I_LOAD:
  564.                 stack[sp++].i = loadgame ();
  565.                 break;
  566.             case I_MINUS:
  567.                 stack[sp-1].i = -stack[sp-1].i;
  568.                 break;
  569.             case I_ADD:
  570.                 sp--;
  571.                 stack[sp-1].i = stack[sp-1].i + stack[sp].i;
  572.                 break;
  573.             case I_SUB:
  574.                 sp--;
  575.                 stack[sp-1].i = stack[sp-1].i - stack[sp].i;
  576.                 break;
  577.             case I_MUL:
  578.                 sp--;
  579.                 stack[sp-1].i = stack[sp-1].i * stack[sp].i;
  580.                 break;
  581.             case I_DIV:
  582.                 sp--;
  583.                 if (!stack[sp].i)
  584.                     perr ("ERROR - Division by zero");
  585.                 stack[sp-1].i = stack[sp-1].i / stack[sp].i;
  586.                 break;
  587.             case I_MOD:
  588.                 sp--;
  589.                 if (!stack[sp].i)
  590.                     perr ("ERROR - Division by zero");
  591.                 stack[sp-1].i = stack[sp-1].i % stack[sp].i;
  592.                 break;
  593.             case I_EQ:
  594.                 sp--;
  595.                 stack[sp-1].i = stack[sp-1].i == stack[sp].i;
  596.                 break;
  597.             case I_NE:
  598.                 sp--;
  599.                 stack[sp-1].i = stack[sp-1].i != stack[sp].i;
  600.                 break;
  601.             case I_GT:
  602.                 sp--;
  603.                 stack[sp-1].i = stack[sp-1].i > stack[sp].i;
  604.                 break;
  605.             case I_LT:
  606.                 sp--;
  607.                 stack[sp-1].i = stack[sp-1].i < stack[sp].i;
  608.                 break;
  609.             case I_GE:
  610.                 sp--;
  611.                 stack[sp-1].i = stack[sp-1].i >= stack[sp].i;
  612.                 break;
  613.             case I_LE:
  614.                 sp--;
  615.                 stack[sp-1].i = stack[sp-1].i <= stack[sp].i;
  616.                 break;
  617.             case I_OEQ:
  618.                 sp--;
  619.                 stack[sp-1].i = stack[sp-1].o == stack[sp].o;
  620.                 break;
  621.             case I_ONE:
  622.                 sp--;
  623.                 stack[sp-1].i = stack[sp-1].o != stack[sp].o;
  624.                 break;
  625.             case I_RANDOM:
  626.                 if (!stack[sp-1].i)
  627.                     perr ("ERROR - Division by zero");
  628.                 stack[sp-1].i = rand () % stack[sp-1].i;
  629.                 break;
  630.             case I_IS:
  631.                 stack[sp-1].i = (classno (stack[sp-1].o) == I.i);
  632.                 break;
  633.             case I_NEXT:
  634.                 if (stack[sp-1].o)
  635.                     if ((stack[sp-1].o = stack[sp-1].o->next) == &objects)
  636.                         stack[sp-1].o = 0;
  637.                 break;
  638.             default:
  639.                 assert (FALSE);
  640.         }
  641.     }
  642.     assert (sp == bp+m->nvars);
  643.     sp = bp;
  644.     return nullv;
  645. }
  646.  
  647. dlist *nountoobject (int n,int methodno)
  648. {
  649.     dlist *o;
  650.     for (o=objects.next ; o!=&objects ; o=o->next)
  651.         if (*classnoptr (o) == n)
  652.         {
  653.             if (methodno < 0)
  654.                 return o;
  655.             var v = applymethod (o,methodno,0);
  656.             if (v.i)
  657.                 return o;
  658.         }
  659.     return 0;
  660. }
  661.  
  662. void docommand (int addressee,int methodno)
  663. {
  664.     int i;
  665.     dlist *ad = vars[0].o;
  666.     if (addressee >= 0)
  667.         if (selectaddresseemethod >= 0)
  668.         {
  669.             ad = nountoobject (addressee,selectaddresseemethod);
  670.             if (ad == 0)
  671.             {
  672.                 if (methods[selectaddresseemethod].noselect >= 0)
  673.                     print (strings[methods[selectaddresseemethod].noselect]);
  674.                 else
  675.                     print ("You can't talk to that.\n");
  676.                 return;
  677.             }
  678.         }
  679.         else
  680.         {
  681.             print ("You can't talk to that.\n");
  682.             return;
  683.         }
  684.     for (i=0 ; i<nnouns ; i++)
  685.         if (methods[methodno].argtypes[i] == T_OBJECT)
  686.         {
  687.             nouns[i].o = nountoobject (nouns[i].i,methods[methodno].selectors[i]);
  688.             if (nouns[i].o == 0)
  689.             {
  690.                 if (methods[methods[methodno].selectors[i]].noselect >= 0)
  691.                     print (strings[methods[methods[methodno].selectors[i]].noselect]);
  692.                 return;
  693.             }
  694.         }
  695.     applymethod (ad,methodno,nouns);
  696. }
  697.  
  698. void command ()
  699. {
  700.     int firstword,addressee,thisword,wordsleft,vwordsleft,vword,nounwords;
  701.     int noun,i,j,k,argno;
  702. REDO:
  703.     getinput ();
  704.     firstword = 0;
  705.     addressee = -1;
  706.     if (comma >= 0)
  707.     {
  708.         if (comma == 0)
  709.         {
  710.             print ("I don't know who you're trying to talk to.\n");
  711.             goto REDO;
  712.         }
  713.         addressee = findclass (words,comma);
  714.         if (addressee < 0)
  715.         {
  716.             print ("I don't know who you're trying to talk to.\n");
  717.             goto REDO;
  718.         }
  719.         nwords -= firstword = comma;
  720.     }
  721.     for (i=0 ; i<nmethods ; i++)
  722.         if (methods[i].nverbs)
  723.             for (j=0 ; j<methods[i].nverbs ; j++)
  724.             {
  725.                 thisword = firstword;
  726.                 wordsleft = nwords;
  727.                 vwordsleft = methods[i].verbs[j].nwords;
  728.                 nnouns = 0;
  729.                 argno = 0;
  730.                 for (k=0 ;; k++)
  731.                 {
  732.                     if (wordsleft == 0)
  733.                     {
  734.                         if (k == methods[i].verbs[j].nwords)
  735.                         {
  736.                             docommand (addressee,i);
  737.                             return;
  738.                         }
  739.                         break;
  740.                     }
  741.                     if (k == methods[i].verbs[j].nwords)
  742.                         break;
  743.                     vwordsleft--;
  744.                     vword = methods[i].verbs[j].words[k];
  745.                     if (vword >= 0)
  746.                     {
  747.                         if (vword != words[thisword])
  748.                             break;
  749.                         thisword++;
  750.                         wordsleft--;
  751.                     }
  752.                     else
  753.                     {
  754.                         if (methods[i].argtypes[argno++] == T_INT)
  755.                         {
  756.                             if (words[thisword] >= 0)
  757.                                 break;
  758.                             nouns[~vword].i = ~words[thisword];
  759.                             thisword++;
  760.                             wordsleft--;
  761.                         }
  762.                         else
  763.                         {
  764.                             nounwords = 0;
  765.                             do
  766.                             {
  767.                                 nounwords++;
  768.                                 if (nounwords+vwordsleft > wordsleft)
  769.                                     break;
  770.                                 noun = findclass (words+thisword,nounwords);
  771.                             }
  772.                             while (noun < 0);
  773.                             if (noun < 0)
  774.                                 break;
  775.                             nouns[~vword].i = noun;
  776.                             thisword += nounwords;
  777.                             wordsleft -= nounwords;
  778.                         }
  779.                         nnouns = Max (nnouns,-vword);
  780.                     }
  781.                 }
  782.             }
  783.     print ("I don't understand you.\n");
  784.     goto REDO;
  785. }
  786.  
  787. main (int argc,char **argv)
  788. {
  789.     int n,i,j,k;
  790.  
  791.     if (argc != 2 || !strcmp (argv[1],"?"))
  792.         perr ("Object-Oriented Adventure Interpreter" VERSION "\n"
  793.                 "Usage: oai filename");
  794.  
  795.     randomize ();
  796.  
  797.     file = Open (argv[1]);
  798.  
  799.     Read (file,buf,4);
  800.     if (memcmp (buf,"oas",4))
  801.         perr ("Not an OASYS file");
  802.  
  803.     n = readint ();
  804.     strings = new char *[n];
  805.     for (i=0 ; i<n ; i++)
  806.     {
  807.         j = readint ();
  808.         strings[i] = new char[j+1];
  809.         Read (file,strings[i],j);
  810.         strings[i][j] = 0;
  811.     }
  812.  
  813.     nvars = readint ();
  814.     vars = new var[nvars];
  815.     vartypes = new int[nvars];
  816.     Read (file,vartypes,nvars * sizeof (int));
  817.  
  818.     nproperties = readint ();
  819.     propertytypes = new int[nproperties];
  820.     Read (file,propertytypes,nproperties * sizeof (int));
  821.  
  822.     nvocab = readint ();
  823.     vocab = new char *[nvocab];
  824.     for (i=0 ; i<nvocab ; i++)
  825.     {
  826.         j = readint ();
  827.         vocab[i] = new char[j+1];
  828.         Read (file,vocab[i],j);
  829.         vocab[i][j] = 0;
  830.     }
  831.  
  832.     nclasses = readint ();
  833.     classes = new Class[nclasses];
  834.     for (i=0 ; i<nclasses ; i++)
  835.     {
  836.         int nphrases = readint ();
  837.         classes[i].nphrases = nphrases;
  838.         if (nphrases)
  839.         {
  840.             classes[i].phrases = new phrase[nphrases];
  841.             for (j=0 ; j<nphrases ; j++)
  842.             {
  843.                 k = readint ();
  844.                 classes[i].phrases[j].nwords = k;
  845.                 classes[i].phrases[j].words = new int[k];
  846.                 Read (file,classes[i].phrases[j].words,k * sizeof (int));
  847.             }
  848.         }
  849.     }
  850.  
  851.     nmethods = readint ();
  852.     methods = new method[nmethods];
  853.     initmethod = readint ();
  854.     selectaddresseemethod = readint ();
  855.     for (i=0 ; i<nmethods ; i++)
  856.     {
  857.         method *m = &methods[i];
  858.         m->type = readint ();
  859.         j = readint ();
  860.         m->nargs = j;
  861.         if (j)
  862.         {
  863.             m->argtypes = new int[j];
  864.             m->selectors = new int[j];
  865.             for (k=0 ; k<j ; k++)
  866.             {
  867.                 m->argtypes[k] = readint ();
  868.                 m->selectors[k] = readint ();
  869.             }
  870.         }
  871.         m->nvars = readint ();
  872.         if (m->nvars)
  873.         {
  874.             m->vartypes = new int[m->nvars];
  875.             Read (file,m->vartypes,m->nvars * sizeof (int));
  876.         }
  877.         int nverbs = readint ();
  878.         m->nverbs = nverbs;
  879.         if (nverbs)
  880.         {
  881.             m->verbs = new phrase[nverbs];
  882.             for (j=0 ; j<nverbs ; j++)
  883.             {
  884.                 k = readint ();
  885.                 m->verbs[j].nwords = k;
  886.                 m->verbs[j].words = new int[k];
  887.                 Read (file,m->verbs[j].words,k * sizeof (int));
  888.             }
  889.         }
  890.         m->noselect = readint ();
  891.         k = readint ();
  892.         m->ninstructions = k;
  893.         if (k)
  894.         {
  895.             m->instructions = new instruction[k];
  896.             Read (file,m->instructions,k * sizeof (instruction));
  897.         }
  898.     }
  899.  
  900.     close (file);
  901.  
  902.     memset (vars,0,nvars * sizeof (var));
  903.     applymethod (0,initmethod,0);
  904.     for (;;)
  905.     {
  906.         assert (sp == 0);
  907.         command ();
  908.         if (restart)
  909.         {
  910.             if (!getyn ("Would you like to play again? (Y/N) "))
  911.                 return 0;
  912.             objects.free ();
  913.             sp = 0;
  914.             memset (vars,0,nvars * sizeof (var));
  915.             restart = FALSE;
  916.             applymethod (0,initmethod,0);
  917.         }
  918.     }
  919. }
  920.